iT邦幫忙

2024 iThome 鐵人賽

DAY 12
1
生成式 AI

Python 新手的 AI 之旅:從零開始打造屬於你的 AI / LLM 應用系列 第 12

【Day12】初探 LLM 評估驅動開發 (Eval-Driven Development) 與 Prompt 生成器:用 AI 來調教 AI

  • 分享至 

  • xImage
  •  

前言

相信經過前幾天的分享,你應該對大型語言模型的操作有更深入的認識,不過你可能也發現一點,就是每次都要自行設計 Prompt,而且還要去測試這個 Prompt 到底好不好,總讓人感覺有點不踏實啊… 有沒有什麼方法是這個 Prompt 有很高的機率很讚、而且可以去測試呢?

接下來我將重寫 Day6 的內容,讓這個會計算字串中英文字母的 LLM 系統更加「穩定」!希望他除了可以算一句話的 strawberry 有幾個 r ,也可以順便算 banana 有幾個 a,不熟悉的朋友可以回到 Day6 複習一下歐。

開發模式

測試驅動開發 (Test-Driven Development, TDD)

測試驅動開發 (TDD) 是一種軟體開發的方法,它強調在寫程式之前,先撰寫測試案例,以確保每一個功能都是可測試的而且符合需求。

TDD 的流程可以概括為三個部分,通常稱為「紅、綠、重構」循環

  • 紅 (Red) :在開始開發功能時,首先為其撰寫測試案例。此時,由於尚未實現該功能,測試必然失敗。
  • 綠 (Green):接下來,開發者撰寫最簡單的程式碼來使得測試通過。此步驟的重點在於實現足夠的功能,讓測試能夠通過,而不關心是否程式碼優化。
  • 重構 (Refactor) :一旦測試通過,開發者便可以重構程式碼,以提高其結構和可讀性,並且再次執行測試,以確保重構後的程式碼仍然通過所有測試。

image.png

有一篇文章寫得很好,可以參考看看〈TDD (Test-Driven Development) 測試驅動開發(入門篇)

不過這種開發方法是針對確定性 (Deterministic) 的系統,對 LLM 應用來說,這種每次的輸出結果具有隨機性 (stochastic) 的系統,應該如何做 TDD 呢?

評估驅動開發 (Eval-Driven Development, EDD)

答案就是做評估 (Evaluation),評估需要準備測試資料集,以及對應的標準答案 (不一定要有),就是很多一問一答,讓 AI 生成答案,然後評估,算出目前的 Promt 可以達到多少準確率

評估方式有以下

  • 人工評估
  • LLM as a Judge:用 GPT-4 等目前知道最厲害的模型來當裁判
  • 對答案:如果有標準答案,就可以直接用程式碼比對 (e.g. 分類問題)

通常我們會讓 AI 產生多個 Prompt,然後保留測試後準確率最高的 Prompt,接下來介紹 Prompt 產生工具以及自動測試 / 最佳化的工具,想看相關研究可以參考論文〈Large Language Models Are Human-Level Prompt Engineers

參考資料:ihower 大大的〈評估驅動開發: 生成式 AI 軟體不確定性的解決方法

Prompt 自動生成工具

以下我就來介紹一些 AI 產生 Prompt 的工具吧!我這次就不用 Day7 用的 OpenAI Tool use API 來噁心大家XD,一樣用自己定義的 <API> token 來表示 function call 的地方,讓模型自行判斷要使用工具的地方。

先看我原本的 Prompt

你的任務是幫助使用者計算字母的數量。
在你要表達數字的地方用 <API>input_string, target_character</API> 來表達。
把 input_string 改成要計算的字串,target_character 改成目標字母。
注意:
1. 不要用引號來包住 input_string 和 target_character。
2. 不要在 input_string 和 target_character 之間加任何符號,例如逗號、空格或其他符號。
3. 不用額外說明計算過程,可以加上自然語言潤飾句子
4. 使用**繁體中文**回答問題。

我們來看看用以下這些工具,他會把我的 Prompt 改成什麼樣子吧!

首先是 Anthropic 的 prompt generator,這個 Anthropic 就是 Claude 模型的公司啦

Automatically generate first draft prompt templates 連結

如果你有訂閱 Claude,那可以直接從 API console 這邊找到 “Grenerate a prompt”

image.png

沒有訂閱的話也沒關係,這邊我使用 Anthropic 提供的 Colab,用 API key 去生成 prompt

填入 API key

image.png

到 Quickstart 這邊修改 TASK,改成你希望它產生的 Prompt 任務內容,你也自定變數 VARIABLES。

image.png

以下是我給他的 TASK prompt

你的任務是幫助使用者計算字母的數量。
你會自動把需要計算字數的地方用 <API>input_string,target_character</API> 來表達。

所以如果問的問題是 strawberry 有多少個 r
你的回答應該會是
strawberry 有 <API>strawberry,r</API> 個 r

把 input_string 改成要計算的字串,target_character 改成目標字母。
注意:
1. 不要用引號來包住 input_string 和 target_character。
2. 不要在 input_string 和 target_character 之間加任何符號,例如逗號、空格或其他符號。
3. 直接在要計算數字的地方用 <API> 不用額外說明計算過程,你就當這個 <API> 是一個數字即可
4. 可以加上自然語言潤飾句子,不要出現不合理的回覆
5. 使用**繁體中文**回答問題。

然後把程式把都執行一遍,最後的 prompt 長這樣

image.png

還有一件事,claude 生成的 Prompt 可能會習慣在答案加上一個 <Answer> 標籤,這部分我們不需要所以可以直接丟掉,如果你還有覺得哪邊寫得不好的也可以自行更改,像這邊我就希望他給的 Few-shot example 用雙引號來包住英文字串而不是上引號

真正最有效的 Prompt 其實是人的經驗 + AI 的知識~

以下是我修改後最終的 Prompt


你是一個協助計算字母數量的AI助手。你的任務是回答使用者關於特定字串中某個字母出現次數的問題。

當需要計算字母數量時,你應該使用以下格式:
<API>input_string,target_character</API>

這個API標籤會自動計算input_string中target_character的出現次數。你應該將這個標籤直接插入到你的回答中,就像它是一個數字一樣。

回答時,請遵循以下指示:
1. 使用繁體中文回答。
2. 直接在需要顯示計算結果的地方使用<API>標籤。
3. 不要解釋計算過程,只需呈現結果。
4. 確保你的回答聽起來自然且合理。

例子:
問題:apple 中有幾個 p ?
回答: "apple" 中有<API>apple,p</API>個"p"。

問題:butterfly裡的t出現了幾次?
回答:在"butterfly" 這個單詞中,t出現了<API>butterfly,t</API>次。

注意事項:
- 不要在<API>標籤內使用引號。
- 在input_string和target_character之間不要加入任何符號(如逗號或空格)。
- 不要額外解釋<API>標籤的功能,直接將它視為計算結果使用。

現在,請回答以下問題:
<question>{$USER_QUESTION}</question>

馬上來試試!這邊因為我 Day6 的程式碼的 format_string 只有考慮一組 <API> 的情況,所以我要改成看到 <API> 都要呼叫計算字數的函式

def format_string(ai_response_string):
    while True:
        start_index = ai_response_string.find("<API>") # 找到 <API> 的開始位置,如果找不到會回傳 -1
        if start_index == -1:
            break
        end_index = ai_response_string.find("</API>", start_index) # 找到 </API> 的結束位置
        if end_index == -1:
            break
        api_content = ai_response_string[start_index+5:end_index] # 取得 API 內容
        input_string, target_character = api_content.split(',') # 分割 input_string 和 target_character
        letter_count = calculate_letter_count(input_string.strip(), target_character.strip()) # 計算字母數量
        ai_response_string = ai_response_string[:start_index] + str(letter_count) + ai_response_string[end_index+6:] # 把計算結果放回 ai_response_string 中
    return ai_response_string

測試結果如下,效果超讚ㄉ (模型選用 gpt-4o-mini)

截圖 2024-09-20 凌晨12.29.53.png

怕篇幅太長,我把程式碼放在 Github 上了,你也可以直接複製出來玩玩看歐

還有其他酷酷的 Prompt 產生器,用法都一樣,跟他說你要叫這個 AI 做什麼任務,他就幫你產生 Prompt ㄌ,不過要記得 AI 生的 Prompt 不見得是最好的,還是要測試、精練 Prompt

不過目前最好用的應該還是 Anthropic Claude

Prompt 最佳化:gpt-prompt-engineer

剛剛有提到評估模型需要用到測試資料集,那測試案例怎麼來?一樣可以用 LLM 幫我們生成資料。聽到這邊你可能想說,又要去複製貼上了…No no no,已經有現成的工具了,而且它幫你把 Prompt 生成到資料評估都做完了,甚至寫成一個 Colab 筆記本,直接使用。

這個工具就是 gpt-prompt-engineer,我們直接下載他的 ipynb 檔案,並到 Colab 上使用。

以剛剛計算英文字數的例子,來寫 Prompt,我們需要修改的有 “In the cell below, fill in your description and test cases” 這邊。

image.png

description = """
你是一個協助計算字母數量的AI助手。你的任務是回答使用者關於特定字串中某個字母出現次數的問題。

當需要計算字母數量時,你應該使用以下格式:
<API>input_string,target_character</API>

這個API標籤會自動計算input_string中target_character的出現次數。你應該將這個標籤直接插入到你的回答中,就像它是一個數字一樣。

回答時,請遵循以下指示:
1. 使用繁體中文回答。
2. 直接在需要顯示計算結果的地方使用<API>標籤。
3. 不要解釋計算過程,只需呈現結果。
4. 確保你的回答聽起來自然且合理。

例子:
問題:apple 中有幾個 p ?
回答: "apple" 中有<API>apple,p</API>個"p"。

問題:butterfly裡的t出現了幾次?
回答:在"butterfly" 這個單詞中,t出現了<API>butterfly,t</API>次。

注意事項:
- 不要在<API>標籤內使用引號。
- 在input_string和target_character之間不要加入任何符號(如逗號或空格)。
- 不要額外解釋<API>標籤的功能,直接將它視為計算結果使用。

現在,請回答以下問題:
""" # this style of description tends to work well

test_cases = [
    {
        'prompt': '請問 banana 有幾個 n',
    },
    {
        'prompt': '請問 strawberry 有幾個 r',
    },
    {
        'prompt': '請問 strawberry 有幾個 r?請問 Banana 有幾個 a? 合併再一起有幾個 a',
    }
]

if use_wandb:
    wandb.config.update({"description": description, 
                        "test_cases": test_cases})

如果你想要的話,也可以去改 CANDIDATE_MODEL, NUMBER_OF_PROMPTS 等等參數,因為我希望他跑快一點所以這邊就把 NUMBER_OF_PROMPTS 設成 3,畢竟是簡單的任務

image.png

執行後他會幫你整理出這三個它產生的 Prompt 的分數 (因為我們設定 3 個 Prompt),再根據需要選出最大就好,只是格式有點醜就是了XD

螢幕錄影 2024-09-20 凌晨2.00.39.gif

測試看看吧!程式碼一樣放在 github 上

image.png

效果也很讚~

其他類似的工具還有:DSPy, AutoPrompt, Textgrad

小結

本篇受 ihower 大大的演講內容的啟發,EDD 讓 LLM 開發的過程從充滿不確定到趨向穩定,真的是很有趣,對我來說也是很新的領域,之後在開發大型語言模型應用的時候也應該要把測試加進去才行。我覺得他有一點說得很好,就是一開始做 POC 大家都覺得很神奇,很厲害,但真的要做 Product 的時候才發現問題好像也蠻多的… 真的很有感!

明天我們終於要稍微脫離程式碼了,我會介紹 Dify / Langflow 等圖形化 LLM 工作流開發工具,期待一下吧!!!


上一篇
【Day11】把知識放到腦袋中:使用 unsloth 微調 (Fine-Tune) 大型語言模型
下一篇
【Day13】告別繁瑣程式碼:初探 Dify / Langflow 等圖形化介面工具來開發 LLM 應用!
系列文
Python 新手的 AI 之旅:從零開始打造屬於你的 AI / LLM 應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言